package com.huilian.iotbox.mqtt.server.base.consumer;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huilian.iotbox.aliyun.service.PubService;
import com.huilian.iotbox.data.cmd.PositiveDataFrameCMD;
import com.huilian.iotbox.data.enums.CompositeDelayQueueEnum;
import com.huilian.iotbox.data.enums.IotBoxCmdEnum;
import com.huilian.iotbox.data.service.DeviceOnlineOfflineRecordCommonService;
import com.huilian.iotbox.data.service.ErrorLogCommonService;
import com.huilian.iotbox.data.vo.DeviceVo;
import com.huilian.iotbox.mqtt.server.base.config.DelayMQConfig;
import com.huilian.iotbox.mqtt.server.base.handler.MessageHandlerStrategy;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Map;

/**
 * MQ处理处理任务类
 *
 * @author: 少凡
 * @Date 2018/11/25 15:56
 */
@Component
@Slf4j
public class RabbitReceiver {

    @Value("${huilian.iot.productKey}")
    private String productKey;
    @Autowired
    private PubService pubService;
    @Autowired
    private ErrorLogCommonService errorLogCommonService;
    @Autowired
    private Map<String, MessageHandlerStrategy> messageHandlerStrategyMap;
    @Autowired
    private DeviceOnlineOfflineRecordCommonService deviceOnlineOfflineRecordCommonService;


    /**
     * 设备心跳
     *
     * @param jsonObject
     * @param channel
     * @param headers
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.queue.name}",
            durable = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.queue.durable}"),
            exchange = @Exchange(value = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.exchange.name}",
                    durable = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.exchange.durable}",
                    type = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.exchange.type}"),
            ignoreDeclarationExceptions = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.exchange.ignoreDeclarationExceptions}",
            key = "${spring.rabbitmq.listener.iotBoxDeviceHeartbeat.key}"))
    @RabbitHandler
    public void deviceHeartbeat(@Payload JSONObject jsonObject, Channel channel, @Headers Map<String, Object> headers) throws IOException {
        log.info("设备心跳-队列：{}", JSON.toJSONString(jsonObject));
        try {
            final String deviceNo = jsonObject.getString("deviceNo");
            final Integer serviceProviderCode = jsonObject.getInteger("serviceProviderCode");
            final String content = jsonObject.getString("content");
            String cmd =IotBoxCmdEnum.AA01DD.getHexadecimal();
            if(!com.aliyuncs.utils.StringUtils.isEmpty(jsonObject.getString("cmd"))){
                cmd =  jsonObject.getString("cmd");
            }
            MessageHandlerStrategy messageHandlerStrategy = messageHandlerStrategyMap.get("messageHandleService" + cmd);
            messageHandlerStrategy.process(content, deviceNo, productKey, serviceProviderCode);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("设备心跳-队列消息处理异常：{}", e.getMessage());
            errorLogCommonService.writerInfoException("设备心跳-队列消息处理异常", jsonObject, e);
        } finally {
            Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
            //手工ACK
            channel.basicAck(deliveryTag, true);
        }
    }


    /**
     * 设备上下线记录
     *
     * @param json
     * @param channel
     * @param headers
     * @throws IOException
     */
    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.queue.name}",
            durable = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.queue.durable}"),
            exchange = @Exchange(value = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.exchange.name}",
                    durable = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.exchange.durable}",
                    type = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.exchange.type}"),
            ignoreDeclarationExceptions = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.exchange.ignoreDeclarationExceptions}",
            key = "${spring.rabbitmq.listener.iotBoxDeviceOnlineOrOffline.key}"))
    @RabbitHandler
    public void deviceOnlineOrOffline(@Payload String json, Channel channel, @Headers Map<String, Object> headers) throws IOException {
        log.info("设备上下线记录-队列：{}", json);
        try {
            final DeviceVo deviceVo = JSON.parseObject(json, DeviceVo.class);
            deviceOnlineOfflineRecordCommonService.updateDeviceOnlineOfflineRecord(deviceVo, deviceVo.getDeviceOnlineOfflineRecordType(), deviceVo.getStartDate(), null);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("设备上下线记录-队列消息处理异常：{}", e.getMessage());
            errorLogCommonService.writerInfoException("设备上下线记录-队列消息处理异常", json, e);
        } finally {
            Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
            //手工ACK
            channel.basicAck(deliveryTag, true);
        }
    }

    @RabbitListener(queues = DelayMQConfig.IOT_BOX_MQTT_LAZY_QUEUE)
    @RabbitHandler
    public void onReplayLazyQueue(@Payload Map<String, String> map, Channel channel, @Headers Map<String, Object> headers) throws IOException {
        try {
            log.info("监听接收到延迟队列消息-延迟发送消息");
            /**
             * 监听接收到延迟队列消息-延迟发送消息
             */
            String code = map.get("code");
            if (CompositeDelayQueueEnum.INITIATIVE_SEND_QUERY_BASE_PARAMS.getCode().equals(code)) {
                // 主动通过串口去查设备的参数
                String tcp = PositiveDataFrameCMD.queryBaseParams();
                log.info("tcp:" + tcp);
                String penetrate = PositiveDataFrameCMD.penetrate(tcp);
                pubService.pub(penetrate, map.get("deviceNo"), productKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
            //手工ACK
            channel.basicAck(deliveryTag, true);
        }
    }
}
